import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;

record UserInfo(String userClass, String userName, String userPasswordHash) {
}

public class UserDataBase {
    private final HashMap<String, UserInfo> userDataBase;
    private String userBaseFileName;

    public UserDataBase() {
        this.userDataBase = new HashMap<>();
        this.userBaseFileName = null;
    }

    public void pullFromFile(String userBaseFileName) throws IOException {
        File file = new File(userBaseFileName);
        if (!file.canRead()) {
            System.out.println("打开用户数据表失败！<" + userBaseFileName + ">");
            throw new IOException();
        }

        ReadLine content = new ReadLine(Files.readString(Paths.get(userBaseFileName)));

        String line = content.readLine();
        while (line != null) {
            String[] tokens = line.split(" ");
            if (tokens.length == 3) {
                String userInfo = tokens[0] + tokens[1];
                UserInfo info = new UserInfo(tokens[0], tokens[1], tokens[2]);
                this.userDataBase.put(userInfo, info);
            }
            line = content.readLine();
        }

        this.userBaseFileName = userBaseFileName;
    }

    public void pushToFile() throws IOException {
        OutputStreamWriter output = new OutputStreamWriter(new FileOutputStream(this.userBaseFileName));

        for (UserInfo info : this.userDataBase.values()) {
            output.write(info.userClass() + " " + info.userName() + " " + info.userPasswordHash() + "\n");
        }

        output.close();
    }

    static String byteToHex(byte[] bytes) {
        StringBuilder buf = new StringBuilder();
        String tmp = null;

        for (byte aByte : bytes) {
            tmp = Integer.toHexString(aByte & 0xff);
            if (tmp.length() == 1) {
                buf.append("0");
            }
            buf.append(tmp);
        }

        return buf.toString();
    }

    public boolean verifyUser(String userClass, String userName, String userPassword) {
        if (this.userBaseFileName == null) {
            return false;
        }

        String userInfo = userClass + userName;
        UserInfo result = this.userDataBase.get(userInfo);

        if (result == null) {
            return false;
        }

        MessageDigest sha256;
        try {
            sha256 = MessageDigest.getInstance("SHA-256");
        } catch (NoSuchAlgorithmException e) {
            System.out.println(e);
            return false;
        }

        byte[] hash = sha256.digest(userPassword.getBytes(StandardCharsets.UTF_8));
        String userPasswordHash = byteToHex(hash);
        return userPasswordHash.compareTo(result.userPasswordHash()) == 0;
    }

    public void insertUser(String userClass, String userName, String userPassword) {
        if (this.userBaseFileName == null) {
            return;
        }

        String userInfo = userClass + userName;
        MessageDigest sha256;

        try {
            sha256 = MessageDigest.getInstance("SHA-256");
        } catch (NoSuchAlgorithmException e) {
            System.out.println(e);
            return;
        }
        byte[] hash = sha256.digest(userPassword.getBytes(StandardCharsets.UTF_8));
        String userPasswordHash = byteToHex(hash);

        UserInfo info = new UserInfo(userClass, userName, userPasswordHash);
        this.userDataBase.put(userInfo, info);
        try {
            this.pushToFile();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
